<template>
  <div class="home-page-layout hor-layout">
    <el-card>
      <div class="hor-layout">
        <div class="ver-layout left-project-layout">
          <div class="hor-layout-center" style="margin-bottom: 10px">
            <span style="color: #333333; font-size: 14px">1.选择模式：</span>
            <el-radio-group v-model="pageData.selModelRadioValue" size="mini">
              <el-radio size="small" label="single">单选模式</el-radio>
              <el-radio size="small" label="multiple">多选模式</el-radio>
            </el-radio-group>
          </div>
          <div class="hor-layout-center" style="margin-bottom: 10px">
            <span style="color: #555555; font-size: 14px">2.展现形式：</span>
            <el-radio-group v-model="pageData.showModelRadioValue" size="mini" @input="radioChange">
              <el-radio size="small" label="tree">树形模式</el-radio>
              <el-radio size="small" label="line">单列模式</el-radio>
            </el-radio-group>
          </div>
          <div class="hor-layout-center" style="margin-bottom: 10px">
            <span style="color: #555555; font-size: 14px">3.项目标签：</span>
            <el-cascader
              clearable
              filterable
              size="small"
              ref="cascaderRef"
              placeholder="选择项目标签"
              v-model="pageData.selProjectFlagList"
              :options="pageData.projectFlagTreeList"
              :props="{ expandTrigger: 'hover', checkStrictly: false }"
              @change="projectFlagChange"
            ></el-cascader>
          </div>
          <el-input
            clearable
            size="small"
            placeholder="输入关键字进行过滤"
            v-model="pageData.filterText"
            @change="inputChange"
          >
          </el-input>
          <div v-if="pageData.showModelRadioValue === 'line'" class="filter-tree1 ver-layout">
            <el-tag
              v-for="(item, index) in filterProjectList"
              :key="item.id"
              size="default"
              class="project-list-item"
              :type="item.selected ? 'primary' : 'info'"
              @mouseover="(e) => showProjectTagTooltip(e, item)"
              @mouseout="(e) => (pageData.tooltipVisible = false)"
              @click="selectProjectItem(item)"
            >
              {{ item.label }}
            </el-tag>
            <!--     提示组件       -->
            <el-tooltip
              ref="tooltipRef"
              :visible="pageData.tooltipVisible"
              :virtual-ref="buttonRef"
              virtual-triggering
              popper-class="singleton-tooltip"
            >
              <template #content>
                <span>{{ pageData.tooltipContent }}</span>
              </template>
            </el-tooltip>
          </div>
          <el-tree
            v-else
            ref="tree2"
            node-key="id"
            show-checkbox
            default-expand-all
            highlight-current
            check-on-click-node
            check-strictly
            :data="pageData.treeData"
            :props="pageData.defaultProps"
            :filter-node-method="filterNode"
            @check-change="handleCheckChange"
            :class="{ 'single-select-tree': pageData.selModelRadioValue == 'single' }"
            class="filter-tree"
          >
          </el-tree>
        </div>
        <div class="project-action-layout ver-layout-center">
          <div class="hor-layout-center" style="margin-bottom: 10px">
            <div>选择的项目：</div>
            <el-button
              :disabled="!canClearSelectUse"
              type="danger"
              size="small"
              @click="clearSelectNode"
            >
              清空选择
            </el-button>
          </div>
          <div class="flex-grid-layout">
            <el-tag
              v-for="(item, index) in pageData.checkNodeList"
              :key="item.id"
              @close="handleClose(item)"
              closable
              size="small"
              class="select-project-item"
            >
              {{ item.label }}
            </el-tag>
          </div>
          <el-button
            type="primary"
            size="small"
            :disabled="!canClearSelectUse"
            @click="openProject"
            class="project-action-view"
          >打开项目
          </el-button>
          <el-button
            type="primary"
            size="small"
            :disabled="!canClearSelectUse"
            @click="openFileDir"
            class="project-action-view"
          >打开文件夹
          </el-button>
          <el-button type="warning" size="small" @click="showCustomCmd" class="project-action-view"
          >自定义命令
          </el-button>
          <div
            id="customCmdInputLayout"
            class="ver-layout-center"
            style="display: flex; width: 100%"
          >
            <el-input
              id="customCmdInputDiv"
              type="textarea"
              :rows="8"
              resize="none"
              :autosize="false"
              v-model="pageData.customCmdText"
              class="custom-cmd-input-view"
            ></el-input>
            <el-radio-group
              v-model="pageData.cmdRadioValue"
              size="mini"
              @change="cmdRadioChange()"
              class="cmd-radio-layout flex-grid-layout"
            >
              <el-radio size="small" label="cd">cd命令</el-radio>
              <el-radio size="small" label="git">git命令</el-radio>
              <!--              <el-radio size="small" label="build_upload_dev">编译部署开发环境</el-radio>-->
              <!--              <el-radio size="small" label="build_upload_test">编译部署测试环境</el-radio>-->
            </el-radio-group>
            <el-button
              :disabled="!pageData.customCmdText"
              type="primary"
              size="small"
              @click="runCustomCmd"
              class="project-action-view"
            >执行自定义命令
            </el-button>
          </div>
        </div>
      </div>
    </el-card>
    <el-card class="log-layout">
      <div id="codeLayout" class="code-layout">
        <code>
          <pre id="sseResView"></pre>
        </code>
      </div>
      <el-button type="danger" size="small" @click="clearLog">清空日志</el-button>
    </el-card>
  </div>
</template>

<script setup lang="ts">
import {ElTree} from 'element-plus'
import {managePlugin} from '../../plugins/managePlugin'
import {computed, nextTick, onMounted, reactive, ref, watch} from 'vue'
import {convertDataToTreeData, convertTreeDataToList} from '../../utils/project/project_utils'
import {appStore} from '../../store/app'

const appStoreObj = appStore()
const tree2 = ref<InstanceType<typeof ElTree>>()
const buttonRef = ref()
const cascaderRef = ref()

const toolsName = computed(() => appStoreObj.toolsName)

//页面数据
const pageData = reactive({
  platform: '',
  defaultProps: {
    children: 'children',
    label: 'label'
  },
  projectFlagTreeList: [],
  cmdRadioMap: {
    //使用``包裹的字段是需要替换成活的字段
    cd: ['pwd'],
    git: ['pwd', 'git branch', 'git log -n 3'],
    build_upload_dev: [
      'pwd',
      'npm run build:pro',
      'rm -rf dist.zip',
      'zip -r dist.zip dist',
      'upload.sh 8.130.43.148 /www/`curProjectName`',
      'open -a "Google Chrome" `devPath`'
    ],
    build_upload_test: [
      'pwd',
      'npm run build:pro',
      'rm -rf dist.zip',
      'zip -r dist.zip dist',
      'upload.sh 43.132.131.88 /www/`curProjectName`',
      'open -a "Google Chrome" `testPath`'
    ]
  },
  exchangeMap: {
    //需要替换成活的字段的对象
    curProjectName: '',
    devPath: '',
    testPath: ''
  },
  showModelRadioValue: 'tree',
  selModelRadioValue: 'single',
  projectList: [],
  treeData: [],
  filterText: '', //搜索文本
  selProjectFlagList: [], //选择的项目标签数组
  selProjectFlagData: {}, //选择的项目标签数组
  checkNodeList: [], //选中的node节点数组
  currentNodeItem: {}, //当前选中的node数据
  customCmdText: '',
  cmdRadioValue: 'cd', //git build_upload
  tooltipVisible: false,
  tooltipContent: ''
})

// 计算属性
const filterProjectList = computed(() => {
  return pageData.projectList.filter((project) => {
    if (pageData.filterText)
      return project.id.toLocaleLowerCase().indexOf(pageData.filterText.toLocaleLowerCase()) > -1
    else if (selFlagLinkProject.value.length) return selFlagLinkProject.value.includes(project.id)
    return true
  })
})

const canClearSelectUse = computed(() => {
  return pageData.checkNodeList.length
})

//选中的标签关联的项目
const selFlagLinkProject = computed(() => {
  let linkProject = pageData.selProjectFlagData.linkProject || []
  linkProject = linkProject.map((item) => item.id)
  console.log('selFlagLinkProject', linkProject)
  return linkProject
})

//监听属性
//根据搜索文本条件执行树的筛选
//根据标签过滤条件执行树的筛选
watch(
  () => pageData.filterText || selFlagLinkProject,
  (val) => {
    if (pageData.showModelRadioValue === 'tree' && tree2.value) tree2.value.filter(val)
  },
  {
    deep: true,
    immediate: true
  }
)

//方法
// 项目的标签改变时
const projectFlagChange = (value) => {
  const checkedNodes = cascaderRef.value.getCheckedNodes()
  const selectedNode = checkedNodes[checkedNodes.length - 1]
  console.log('projectFlagChange==', value, selectedNode)
  pageData.selProjectFlagData = (selectedNode && selectedNode.data) || {}
}

//显示标签备注
const showProjectTagTooltip = (e, item) => {
  buttonRef.value = e.currentTarget
  pageData.tooltipVisible = true
  pageData.tooltipContent = item.id.replace(/,/g, '/')
}

//过滤tree的数据
const filterNode = (value, project) => {
  if (pageData.filterText)
    return project.id.toLocaleLowerCase().indexOf(pageData.filterText.toLocaleLowerCase()) > -1
  else if (selFlagLinkProject.value.length) return selFlagLinkProject.value.includes(project.id)
  return true
}

// 选择radio事件
const radioChange = (val) => {
  if (val === 'tree') {
    nextTick(() => {
      tree2.value.filter()
      tree2.value.setCheckedKeys(pageData.checkNodeList.map((item) => item.id))
    })
  }
}

//tree选择事件
//在切换选择项的时候，新选择的和之前撤销选择的都会进来【这里是最麻烦的】。这里只判断最新的是新选择的，或者最新选择的和之前的一样的。
const handleCheckChange = (data, checked, indeterminate) => {
  if (checked) selectProjectItem(data)
  else if (data.id === pageData.currentNodeItem.id && pageData.checkNodeList.length)
    selectProjectItem(data)
  //上面判断pageData.checkNodeList.length是区分是否点的清空按钮触发的。
}

//关闭选择的tag事件
const handleClose = (node) => {
  selectProjectItem(node)
}

//选择项目
const selectProjectItem = (node) => {
  console.log('node.id=====', node.id)
  pageData.projectList = pageData.projectList.map((item) => {
    if (item.id === node.id) item.selected = !item.selected
    else if (pageData.selModelRadioValue === 'single') item.selected = false
    return item
  })
  pageData.checkNodeList = pageData.projectList.filter((item) => item.selected)
  //如果显示是树模式，并且选择的节点和之前的节点不一致就 手动设置树选择的数据
  if (
    pageData.showModelRadioValue === 'tree' &&
    pageData.currentNodeItem.id &&
    pageData.currentNodeItem.id !== node.id
  ) {
    tree2.value.setCheckedKeys(pageData.checkNodeList.map((item) => item.id))
  }
  genExchangeMapData()
  cmdRadioChange()
}

//生成替换对象的数据
const genExchangeMapData = () => {
  pageData.currentNodeItem = (pageData.checkNodeList.length && pageData.checkNodeList[0]) || {}
  pageData.exchangeMap.curProjectName = pageData.currentNodeItem.label
  pageData.exchangeMap.devPath = pageData.currentNodeItem.devPath
  pageData.exchangeMap.testPath = pageData.currentNodeItem.testPath
}

//清空选择的节点
const clearSelectNode = () => {
  pageData.projectList = pageData.projectList.map((item) => {
    item.selected = false
    return item
  })
  pageData.checkNodeList = []
  pageData.currentNodeItem = {}
  tree2.value.setCheckedKeys([])
}

//获取节点的绝对路径
const getNodeAbsolutePath = (node) => {
  let basePath = '',connector = pageData.platform == 'window' ? '\\' : '/'
  let nodePath = node.id.replace(/,/g, connector)
  return `${basePath}${nodePath}`
}

//显示/隐藏自定义命令输入框
const showCustomCmd = () => {
  let displayStyle = document.getElementById('customCmdInputLayout').style.display
  document.getElementById('customCmdInputLayout').style.display =
    displayStyle === 'flex' ? 'none' : 'flex'
  cmdRadioChange()
}

//获取需要替换字段的活数据的字段
const exchangeMapByLiveData = (str) => {
  console.log('pageData.exchangeMap', pageData.exchangeMap)
  let replaceStr = str
    .split('`')
    .filter((item) => item)
    .map((item) => {
      if (pageData.exchangeMap.hasOwnProperty(item)) item = pageData.exchangeMap[item]
      return item
    })
    .join('')
  return replaceStr
}

//自定义命令选择事件
const cmdRadioChange = () => {
  let cmdList = pageData.cmdRadioMap[pageData.cmdRadioValue]
  //在数组最前面添加一个cd命令
  if (pageData.checkNodeList.length) {
    //将自定义命令数组中的替换字段 使用exchangeMap的活数据替换了。
    cmdList = cmdList.map((item) => {
      if (item.indexOf('`') !== -1) {
        item = exchangeMapByLiveData(item)
      }
      return item
    })
    cmdList = [`cd ${getNodeAbsolutePath(pageData.currentNodeItem)}`, ...cmdList]
  }
  pageData.customCmdText = cmdList.join('\n')
}

//清除日志按钮
const clearLog = () => {
  let sseResView = document.getElementById('sseResView')
  sseResView.innerHTML = ''
}

//打开项目
const openProject = () => {
  let commandStart = 'webstorm'
  if (pageData.platform == 'window') {
    commandStart = toolsName.value == 'webstorm' ? 'start webstorm64.exe' : 'code'
  } else if (pageData.platform == 'mac') {
    commandStart = toolsName.value == 'webstorm' ? 'webstorm' : 'code'
  }
  console.log('commandStart==', commandStart)
  let openFileCmdList = pageData.checkNodeList.map((item) => {
    return `${commandStart} ${getNodeAbsolutePath(item)}`
  })
  runCommandStart(openFileCmdList)
}

//打开文件夹
const openFileDir = () => {
  let commandStart = 'open'
  if (pageData.platform == 'window') {
    commandStart = 'start'
  } else if (pageData.platform == 'mac') {
    commandStart = 'open'
  }
  let openFileCmdList = pageData.checkNodeList.map((item) => {
    return `${commandStart} ${getNodeAbsolutePath(item)}`
  })
  runCommandStart(openFileCmdList)
}

//执行自定义命令
const runCustomCmd = () => {
  let customCmdList = pageData.customCmdText.split('\n').filter((item) => item)
  runCommandStart(customCmdList)
}

const inputChange = (val) => {
  console.log('inputChange', val)
}

//执行命令开始
const runCommandStart = (customCmdList) => {
  managePlugin.runCmdRender(customCmdList)
  let sseResView = document.getElementById('sseResView')
  let emptyLine = `<p style="color:blue;margin: 0">=============================</p>`
  sseResView.innerHTML = sseResView.innerHTML + emptyLine
}

//执行命令行回调
const runCommandBack = (data) => {
  let sseResView = document.getElementById('sseResView')
  let codeLayout = document.getElementById('codeLayout')
  data = data.replace(/data:/g, '')
  let color = data.indexOf('####') === -1 ? 'black' : '#00CD7F'
  let fontSize = data.indexOf('####') === -1 ? '12px' : '13px'
  let codeLine = `<p style="color:${color};font-size:${fontSize};margin: 0;padding: 5px 0px">${data}</p>`
  sseResView.innerHTML = sseResView.innerHTML + codeLine
  codeLayout.scrollTop = codeLayout.scrollHeight
}

//页面渲染时
onMounted(async () => {
  console.log('home-onMounted')
  let projectData = await managePlugin.getProjectDirsRender()
  console.log('projectData===', projectData)
  let projectTreeList = convertDataToTreeData(projectData)
  console.log('projectTreeList===', projectTreeList)
  pageData.treeData = projectTreeList
  pageData.projectList = convertTreeDataToList(projectTreeList)
  pageData.projectFlagTreeList = await managePlugin.getProjectFlagRender({removeAddFlag: true})
  pageData.platform = await managePlugin.getPlatformRender()
  console.log('home-pageData.projectFlagTreeList', pageData.projectFlagTreeList)
  managePlugin.handleReceiveMessageRender((val1) => {
    console.log('handleReceiveMessageRender', val1)
    runCommandBack(val1)
  })
})
</script>

<style scoped lang="less">
@import '../../assets/css/project.css';

.single-select-tree /deep/ .el-checkbox__inner {
  border-radius: 50%;
}

.home-page-layout {
  background: #0a3fa8;
  padding: 10px;
  overflow-y: hidden;
}

/deep/ .log-layout > .el-card__body {
  padding: 7px;
}

.singleton-tooltip {
  transition: transform 0.3s var(--el-transition-function-fast-bezier);
}
</style>
